// 默认是Map是immutable的，如果要创建可以修改的Map，使用scala.collection.mutable.Map
// 使用apply方式创建Map： 
val m1 = Map(123->"eh", 323->"jasldkf")
val m2 = Map((123,"hello"),(332,"jasdf"))

// 如果想从一个空的集合开始，使用:
val m3 = new scala.collection.mutable.HashMap[Int,String]

// map基本操作：
map.contains(89)
if (map.contains(89)) map(89) else 0
// 简写：map.getOrElse(89, "xyz") // 如果map中没有key为89的元素，则返回0
// 更新map中的值：
map(89)="sadfk9o12"  // 只有map是可变的才行
map += (301->"301",302->"302")  // 一次添加多个元素
map -= (301) // 移除元素
// 如果map是不可变的，val m = Map(123->"haha")默认生成不可变的Map,也可以用 m + (123->"123",124->"124") 来生成另外一个map，原先的123被更新了,新添加了124
// 同理，可以用-号来移除一个元素，同时生成一个新的Map

// 遍历一个map
for ((k,v)<- map) //一般形式
for (i<-map.keySet)  for (i<-map.values)  // 遍历Key和Value
for ((k,v)<-map) yield (v,k)  // 反转key和value

// 排序Map
scala.collection.immutable.SortedMap("jack"->33, "tom"->87, "alice"->16, "henry"-> 28)
// 按插入顺序排序Map
scala.collection.mutable.LinkedHashMap("jack"->33, "tom"->87, "alice"->16, "henry"-> 28)

// 与Java的互操作，又是隐式转换，treeMap -> mutable.Map
import scala.collection.JavaConversions.mapAsScalaMap
val scores:scala.collection.mutable.Map[String,Int] = new java.util.TreeMap[String, Int]
// java properties -> mutable.Map prop一定要指定类型，不然会被指定为Properties类型，import也是必须的，不然怎么会“转换”呢？
import scala.collection.JavaConversions.propertiesAsScalaMap
val prop:scala.collection.mutable.Map[String,String] = System.getProperties()


// 元组是不同类型的值的聚集
// (12, true, "hello") 类型为 Tuple[Int, Boolean, java.lang.String]， 也可以简写为(Int,Boolean,java.lang.String)
// 访问元组的元素：  t._2 可以写成t _2 ，但不能写成t_2
val t = (1,3.14, "hello")
t._1
t._2
t._3
// 使用模式匹配来获得所有的组元：
val (v1,v2,v3) = t
// 如果并不是所有的值都需要，则可以在不需要的值的位置用_代替：
val (a1,_,a3) = t
// 元组经常用在返回值不至一个的情况下：partition 是 StringOps的方法，返回的是一对字符串，包含满足条件和不满足条件的字符
val (v1,v2) = "New York".partition(_.isUpper)
val (v1,v2) = "New York 110".partition(_.isDigit)

// zip函数，如果两个集合的长度不一样，多出来的部分会被zip函数舍弃
val a = Array(1,2,3)
val b = Array("hello","world","scala")
val c = a.zip(b)
// 生成结果的类型是[Array[Tuple2]]，可以用下面的方式来操作：
for ((s,n)<-c) println (n*s)
// 也可以用toMap的方式生成Map

val a = Array(1,2,3,4,5)
val b = Array("hello","world","scala")
val c = a.zip(b).toMap



import java.io.File
import java.util.Scanner
import java.util.StringTokenizer
import scala.collection.SortedMap
import scala.collection.JavaConverters._

object charpter04 {
  /*
   * 4.1
   * 设置一个映射, 其中包含你想要的一些装备,以及它们的价格,
   * 然后构建另一个映射, 采用同一组键, 但在价格上打9折
   */

def q1(a:Map[String,Double]):Map[String,Double]={
for((k,v)<- a) yield (k,v*0.9)
}
q1(Map("apple"->8,"banana"->7, "watermelon"->10))


  def question1(origin: Map[String, Double]): Map[String, Double] = {
    for ((k, v) <- origin) yield (k, 0.9 * v)
  }

  /*
   * 4.2
   * 编写一段程序, 从文件中读取单次, 用一个可变映射来清点每一个单次出现的频率,
   * 读取这些单次的操作可以使用java.util.Scanner,
   * val in = new java.util.Scanner(new java.io.File("myfile.txt:)),
   * while(in.hasNext()) 处理 in.next() 最后, 打印出所有单次和它们出现的次数
   */
// 用可变映射实现
val m:Map[String,Int] = scala.collection.mutable.HashMap()
val lines = scala.io.Source.fromFile("c:/c.log").getLines
for (l<-lines) {
val ss = l.split(" ")
for (s<-ss if s.trim != "") {
m(s) = m.getOrElse(s,0) + 1
}
}
m foreach println

// 用不可变集合实现
var m:Map[String,Int] = Map[String,Int]()
val lines = scala.io.Source.fromFile("c:/c.log").getLines
for (l<-lines) {
val ss = l.split(" ")
for (s<-ss if s.trim != "") {
m = m + (s -> (m.getOrElse(s,0) + 1)) // 这里不能用m.+=(s->n) ，不解 ，下面的函数里就可以
}
}
m foreach println

// 用已排序的集合
var m = SortedMap[String,Int]()
val lines = scala.io.Source.fromFile("c:/c.log").getLines
for (l<-lines) {
val ss = l.split(" ")
for (s<-ss if s.trim != "") {
m = m + (s -> (m.getOrElse(s,0) + 1)) // 这里不能用m.+=(s->n) ，不解 ，下面的函数里就可以
}
}
m foreach println


// 使用Java的TreeMap并使之适用于scala API
def q5(path:String):scala.collection.mutable.Map[String,Int] = {
var m = new java.util.TreeMap[String,Int]()
import scala.collection.JavaConversions._
val lines = scala.io.Source.fromFile(path).getLines
for (l<-lines) {
val ss = l.split(" ")
for (s<-ss if s.trim != "") {
m(s) = m.getOrElse(s,0) + 1
}
}
m
}


  def question2(path: String): scala.collection.mutable.Map[String, Int] = {
    import scala.collection.mutable.Map

    val res = Map[String, Int]()
    val in = new Scanner(new File(path))
    while (in.hasNext()) {
      val st = new StringTokenizer(in.next())
      while (st.hasMoreTokens()) {
        val key = st.nextToken()
        res(key) = res.getOrElse(key, 0) + 1
      }
    }
    res
  }

  /*
   * 4.3
   * 重复前一个联系,这次用不可变的映射
   */
  def question3(path: String): Map[String, Int] = {
    var res = Map[String, Int]()
    val in = new Scanner(new File(path))
    while (in.hasNext()) {
      val st = new StringTokenizer(in.next())
      while (st.hasMoreTokens()) {
        val key = st.nextToken()
        res += (key -> (res.getOrElse(key, 0) + 1))
      }
    }
    res
  }

  /*
   * 4.4
   * 重复前一个联系, 这次用已排序的映射,一遍单次可以按顺序打印出来
   */
  def question4(path: String): SortedMap[String, Int] = {
    var res = SortedMap[String, Int]()
    val in = new Scanner(new File(path))
    while (in.hasNext()) {
      val st = new StringTokenizer(in.next())
      while (st.hasMoreTokens()) {
        val key = st.nextToken()
        res += (key -> (res.getOrElse(key, 0) + 1))
      }
    }
    res
  }

  /*
   * 4.5
   * 重复前一个联系, 这次用java.util.TreeMap并使之适用于ScalaAPI
   */
  def question5(path: String): scala.collection.mutable.Map[String, Int] = {
    import java.util.TreeMap

    var res = new TreeMap[String, Int].asScala
    val in = new Scanner(new File(path))
    while (in.hasNext()) {
      val st = new StringTokenizer(in.next())
      while (st.hasMoreTokens()) {
        val key = st.nextToken()
        res(key) = res.getOrElse(key, 0) + 1
      }
    }
    res
  }

  /*
   * 4.6
   * 定义一个链式哈希映射, 将"Monday"映射到java.util.Calendar.MONDAY,
   * 以此类推假如其他日期, 展示元素是以插入的顺序被访问的
   */
  def question6(): Map[String, Int] = {
    var map = Map[String, Int]()
    val list = classOf[java.util.Calendar].getFields
    list foreach { x => map += (x.getName -> x.getInt(null)) }
    map
  }

// 没有返回值，不需要加=，即为方法，而不是函数
def q7() {
val m = System.getProperties().toMap
val maxlen = m.map(x=>x._1.length).max
m foreach { x=>println(x._1 + " " * (maxlen - x._1.length) + " | " + x._2) }
}
q7

  /*
   * 4.7
   * 打印出所有Java系统属性的表格, 类似这样:
   * java.vm.info                  | mixed mode
   * java.version                  | 1.7.0_67
   * sun.cpu.endian                | little
   * sun.desktop                   | windows
   * sun.cpu.isalist               | amd64
   */

val prop = System.getProperties();

  def question7() {
    val props = System.getProperties().asScala
    val manlen = props.map(f => f._1.length).max

    props foreach { x => println(x._1 + " " * (manlen - x._1.length + 1) + "| " + x._2) }
  }

  /*
   * 4.8
   * 编写一个函数minmax(values: Array[Int]), 返回数组中最小值和最大值的对偶
   */
def q8(arr:Array[Int]) : Tuple2[Int,Int] = {
(arr.min, arr.max)
}


  def question8(values: Array[Int]): Tuple2[Int, Int] = {
    (values.min, values.max)
  }

  /*
   * 4.9
   * 编写一个函数lteqgt(values: Array[Int], v: Int),
   * 返回数组中小于v 等于v 和 大于v的数量, 要求三个值一起返回
   */
def q9(arr:Array[Int],v:Int):Tuple3[Int,Int,Int] = {
(arr.filter(_<v).length,arr.filter(_==v).length,arr.filter(_>v).length)
}
  def question9(values: Array[Int], v: Int) = {
    (values.count { _ < v }, values.count { _ == v }, values.count { _ > v })
  }

  /*
   * 4.10
   * 当你将两个字符串拉链在一起, 比如"Hello" zip "World", 回事什么结果?
   * 想处一个讲的通的用例
   */
  def question10() = {
    Predef println ("Hello" zip "World")
  }

  def main(args: Array[String]): Unit = {
    //    question5("test.txt") foreach { x => println(x._1 + " -> " + x._2) }
    question7()
  }
}